package juc.utils.phaser;

import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;

/**
 * 有几点注意：
 * 当签到的人员数量等于到达会场人员数量，将立即开会，所以第一个人员到达会场会比最后一个签到的晚才能保证所有人能参加会议。
 * 可以一个会场容纳所有人开会，将同一个phaser传递给所有的task；也可以维护一个层级关系，建立多个会场进行同一个会议，将所有参会人员平均分配到各个会场。
 * 签到之后，可以不用等待所有人到达会场可以立即离场，并且从签到簿上抹掉签名。
 * 下一场会议开始之前，如果还有人员等待下一场会议，那么所有签到的人都必须参加下一场。如果所有人都不等待，会议结束。
 * 所有人员参加完指定数量的会议后，会议结束。
 * <p>
 * Phaser终止的两种途径，Phaser维护的线程执行完毕或者onAdvance()返回true
 * 此外Phaser还能维护一个树状的层级关系，构造的时候new Phaser(parentPhaser)，对于Task执行时间短的场景（竞争激烈），** TASKS_PER_PHASER**值设置较小，反之适当增大。
 * <p>
 * 名词解释：
 * <p>
 * party 对应一个线程，数量可以通过register或者初始化new Phaser(num)的时候控制
 * arrive 对应一个party的状态，初始时是unarrived，当调用arriveAndAwaitAdvance()或者 arriveAndDeregister()进入arrive状态，可以通过getUnarrivedParties()获取当前未到达的数量
 * register 注册一个party，每一阶段必须所有注册的party都到达才能进入下一阶段
 * phase 阶段，当所有注册的party都arrive之后，将会调用Phaser的onAdvance()方法来判断是否要进入下一阶段
 * phase，即Phaser的年龄，当未到达的parties减到0（即所有parties已到达）时，phase自动加1，并且把16-31位的parties数复制到0-15位，从而该Phaser可以继续复用
 * <p>
 * 作者：进击de大黄
 * 链接：https://www.jianshu.com/p/a9a713cba61a
 * 来源：简书
 * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
 */
public class PhaserSamples {

    public static void main(String[] args) throws InterruptedException {
        new PhaserSamples().runTasks();

    }

    // 一共开几场会
    private static final int PHASE_TO_TERMINATE = 2;
    // 初始参会人员数量
    private static final int INIT_PARTIES = 1;
    // 增加参会人员数量
    private static final int ADD_PARTIES = 5;
    // 每个会场限制参会者数量
    private static final int TASKS_PER_PHASER = 3;

    void runTasks() throws InterruptedException {
        final Phaser phaser = new Phaser(INIT_PARTIES) {
            // 所有人员到达完毕，开始会议；连续开PHASE_TO_TERMINATE - 1 场会议，会议结束（terminal）
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                System.out.println("第" + (phase + 1) + "场会议结束");
                //return registeredParties == 0;
                //System.out.println(registeredParties);//5
                return phase == (PHASE_TO_TERMINATE - 1) || registeredParties == 0;
            }
        };
        final Task tasks[] = new Task[ADD_PARTIES];

        System.out.println("会议开始准备,需要至少" + INIT_PARTIES + "人签到, 共连续" + PHASE_TO_TERMINATE + "场会议,分会场数量" +
                (ADD_PARTIES % TASKS_PER_PHASER == 0 ? (ADD_PARTIES / TASKS_PER_PHASER) : (ADD_PARTIES / TASKS_PER_PHASER + 1)));
        System.out.println("Main准备参加第一场会议,开始签到,共" + phaser.getRegisteredParties() + "人签到");

        build(tasks, 0, tasks.length, phaser);
        for (int i = 0; i < tasks.length; i++) {
            final Thread thread = new Thread(tasks[i]);
            thread.start();
        }

        phaser.arriveAndDeregister();
        System.out.println("Main离开会场");
        // 准备下一场会议，如果没有再到达会场，所有人都将等待
//        phaser.arriveAndAwaitAdvance();
//        System.out.println("Main休息准备下一场会议");
    }

    //这段代码写得精妙！
    public static void build(Task[] tasks, int lo, int hi, Phaser ph) {
        if (hi - lo > TASKS_PER_PHASER) {
            for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
                int j = Math.min(i + TASKS_PER_PHASER, hi);
                build(tasks, i, j, new Phaser(ph));
            }
        } else {
            for (int i = lo; i < hi; ++i)
                tasks[i] = new Task(i + 1, ph);
        }
    }


    public static class Task implements Runnable {
        private final int id;
        private final Phaser phaser;

        public Task(int id, Phaser phaser) {
            this.id = id;
            this.phaser = phaser;
            this.phaser.register();
            System.out.println("参会人员" + id + "已经签到,共" + phaser.getRegisteredParties() + "人签到");
        }

        @Override
        public void run() {
            // 参加每一场会议
            while (!phaser.isTerminated()) {
                try {
                    // 签到之后，走到会场
                    Thread.sleep(20 * id + 20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("参会人员" + this.id + "已经到达第" + (phaser.getPhase() + 1) + "场会议, 当前共有"
                        + phaser.getRegisteredParties() + " 人参会,"
                        + (phaser.getArrivedParties() + 1) + " 到达,"
                        + (phaser.getUnarrivedParties() - 1) + " 未到达");
                // 到达会场
                phaser.arriveAndAwaitAdvance();
            }
        }
    }
}